#include "stdafx.h"
#include "charset/textencode.hpp"
#include "charset/textiterator.hpp"
#include "charset/textconverter.hpp"
#include "stdlib/bugcheck.hpp"
using namespace JHCPP::stdlib;

namespace JHCPP
{
	namespace charset
	{	
		int nullTransform(int ch)
		{
			return ch;
		}

		CTextConverter::CTextConverter(const CTextEncode& inEncode, const CTextEncode& outEncode, int defaultChar)
		:m_inEncode(inEncode),
		m_outEncode(outEncode),
		m_defaultChar(defaultChar)
		{
		}

		CTextConverter::~CTextConverter()
		{
		}

		int CTextConverter::convert(const std::string& source, std::string& destination, Transform trans)
		{
			int errors = 0;
			CTextIterator it(source, m_inEncode);
			CTextIterator end(source);
			unsigned char buffer[CTextEncode::MAX_SEQUENCE_LENGTH];

			while (it != end)
			{
				int c = *it;
				if (c == -1) { ++errors; c = m_defaultChar; }
				c = trans(c);
				int n = m_outEncode.convert(c, buffer, sizeof(buffer));
				if (n == 0) n = m_outEncode.convert(m_defaultChar, buffer, sizeof(buffer));
				jh_assert (n <= sizeof(buffer));
				destination.append((const char*) buffer, n);
				++it;
			}
			return errors;
		}

		int CTextConverter::convert(const void* source, int length, std::string& destination, Transform trans)
		{
			jh_check_ptr (source);

			int errors = 0;
			const unsigned char* it  = (const unsigned char*) source;
			const unsigned char* end = (const unsigned char*) source + length;
			unsigned char buffer[CTextEncode::MAX_SEQUENCE_LENGTH];

			while (it < end)
			{
				int n = m_inEncode.queryConvert(it, 1);
				int uc;
				int read = 1;

				while (-1 > n && (end - it) >= -n)
				{
					read = -n;
					n = m_inEncode.queryConvert(it, read);
				}

				if (-1 > n)
				{
					it = end;
				}
				else
				{
					it += read;
				}

				if (-1 >= n)
				{
					uc = m_defaultChar;
					++errors;
				}
				else
				{
					uc = n;
				}

				uc = trans(uc);
				n = m_outEncode.convert(uc, buffer, sizeof(buffer));
				if (n == 0) n = m_outEncode.convert(m_defaultChar, buffer, sizeof(buffer));
				jh_assert (n <= sizeof(buffer));
				destination.append((const char*) buffer, n);
			}
			return errors;
		}

		int CTextConverter::convert(const std::string& source, std::string& destination)
		{
			return convert(source, destination, nullTransform);
		}

		int CTextConverter::convert(const void* source, int length, std::string& destination)
		{
			return convert(source, length, destination, nullTransform);
		}

	}//end of namespace charset
}//end of namespace JHCPP
